package com.yanghui.dtracing.core.opentracing;

import io.opentracing.SpanContext;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author nick.yang
 * @since 2021.03.19
 */
@Getter
@ToString
public class DTracerSpanContext implements SpanContext {

    protected static final String ROOT_SPAN_ID = "0";

    protected static final String ROOT_PID = "-1";

    /**追踪ID**/
    private final String traceId;

    /**spanId 形如 rootSpanId:0 其他 0.1  0.2  0.3  0.1.1**/
    private final String spanId;//

    /**父 spanID**/
    @Setter
    private final String parentId;

    /**
     * 是否采样
     */
    @Setter
    private boolean sampled;

    private final Map<String,String> baggageItems = new HashMap<>();

    @Setter
    private AtomicInteger childContextIndex = new AtomicInteger(0);

    public DTracerSpanContext(String traceId){
        this(traceId,ROOT_SPAN_ID,ROOT_PID,true);
    }

    public DTracerSpanContext(String traceId, String spanId){
        this(traceId,spanId,ROOT_PID,true);
    }

    public DTracerSpanContext(String traceId, String spanId,String parentId){
        this(traceId,spanId,parentId,true);
    }

    public DTracerSpanContext(String traceId, String spanId, String parentId,boolean sampled){
        this.traceId = traceId;
        this.spanId = spanId;
        this.sampled = sampled;
        this.parentId = parentId;
    }

    @Override
    public String toTraceId() {
        return this.traceId;
    }

    @Override
    public String toSpanId() {
        return this.spanId;
    }

    @Override
    public Iterable<Map.Entry<String, String>> baggageItems() {
        return baggageItems.entrySet();
    }

    public void addBaggageItem(String key,String value){
        this.baggageItems.put(key,value);
    }

    public void addBaggageItems(Map<String,String> baggageItems){
        this.baggageItems.putAll(baggageItems);
    }

    public String getBaggageItem(String key){
        return this.baggageItems.get(key);
    }


    public DTracerSpanContext clone(){
        DTracerSpanContext context = new DTracerSpanContext(this.traceId,this.spanId,this.parentId,this.sampled);
        for(Map.Entry<String,String> entry : this.baggageItems.entrySet()){
            context.addBaggageItem(entry.getKey(),entry.getValue());
        }
        return context;
    }

    public String nextChildSpanId(){
        return this.spanId + "." + this.childContextIndex.incrementAndGet();
    }
}
